package com.minimalist.basic.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import com.minimalist.basic.config.fileHandler.FileManager;
import com.minimalist.basic.config.fileHandler.handler.FileHandler;
import com.minimalist.basic.mapper.MFileMapper;
import com.minimalist.basic.mapper.MStorageMapper;
import com.minimalist.basic.mapper.MTenantMapper;
import com.minimalist.basic.service.FileService;
import com.minimalist.common.config.exception.BusinessException;
import com.minimalist.common.config.mybatis.bo.PageResp;
import com.minimalist.common.entity.basic.enums.FileEnum;
import com.minimalist.common.entity.basic.enums.StorageEnum;
import com.minimalist.common.entity.basic.enums.TenantEnum;
import com.minimalist.common.entity.basic.po.MFile;
import com.minimalist.common.entity.basic.po.MStorage;
import com.minimalist.common.entity.basic.po.MTenant;
import com.minimalist.common.entity.basic.vo.file.*;
import com.minimalist.common.utils.SafetyUtil;
import com.mybatisflex.core.logicdelete.LogicDeleteManager;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.tenant.TenantManager;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.util.List;

/**
 * @author 11987
 */
@Service
public class FileServiceImpl implements FileService{

    private static final Logger log = LoggerFactory.getLogger(FileServiceImpl.class);

    @Autowired
    private MFileMapper fileMapper;

    @Autowired
    private MStorageMapper storageMapper;

    @Autowired
    private FileManager fileManager;

    @Autowired
    private MTenantMapper tenantMapper;

    /**
     * 单文件上传
     *
     * @param fileUploadVO 文件及携带参数
     * @return 文件信息
     */
    @Override
    public FileUploadRespVO uploadFile(FileUploadVO fileUploadVO){
        MStorage storage = getStorage(fileUploadVO.getStorageId());
        Assert.notNull(storage, () -> new BusinessException(StorageEnum.ErrorMsg.NONENTITY_STORAGE.getDesc()));
        FileHandler fileHandler = fileManager.getFileHandler(storage.getStorageType());
        //上传文件
        MFile mFile = fileHandler.uploadFile(fileUploadVO.getFile(), fileUploadVO.getFileSource(), storage);
        fileMapper.insert(mFile, true);
        return BeanUtil.copyProperties(mFile, FileUploadRespVO.class);
    }

    /**
     * 多上传文件
     *
     * @param uploadBatchVO 文件及携带参数
     * @return 文件信息
     */
    @Override
    public List<FileUploadRespVO> uploadFileBatch(FileUploadBatchVO uploadBatchVO){
        MStorage storage = getStorage(uploadBatchVO.getStorageId());
        Assert.notNull(storage, () -> new BusinessException(StorageEnum.ErrorMsg.NONENTITY_STORAGE.getDesc()));
        FileHandler fileHandler = fileManager.getFileHandler(storage.getStorageType());
        //循环上传多个文件
        List<MFile> files = CollectionUtil.list(false);
        for (MultipartFile file : uploadBatchVO.getFiles()){
            MFile mFile = fileHandler.uploadFile(file, uploadBatchVO.getFileSource(), storage);
            files.add(mFile);
        }
        //批量插入文件信息
        fileMapper.insertBatch(files);
        return BeanUtil.copyToList(files, FileUploadRespVO.class);
    }

    /**
     * 删除文件
     *
     * @param fileId 文件ID
     */
    @Override
    public void deleteFile(Long fileId){
        //查询文件
        MFile mFile = fileMapper.selectFileByFileId(fileId);
        Assert.notNull(mFile, () -> new BusinessException(FileEnum.ErrorMsg.NONENTITY_FILE.getDesc()));
        MStorage storage = getStorage(mFile.getStorageId());
        FileHandler fileHandler = fileManager.getFileHandler(storage.getStorageType());
        //删除文件
        fileHandler.deleteFile(mFile, storage);
        //删除数据库文件记录
        LogicDeleteManager.execWithoutLogicDelete(() ->
                fileMapper.deleteByQuery(QueryWrapper.create().eq(MFile::getFileId, fileId))
        );
    }

    /**
     * 查询文件列表(分页)
     *
     * @param queryVO 查询条件
     * @return 文件分页数据
     */
    @Override
    public PageResp<FileVO> getPageFileList(FileQueryVO queryVO){
        Page<MFile> filePage = fileMapper.selectPageFileList(queryVO);
        //数据转换
        List<FileVO> fileVOList = BeanUtil.copyToList(filePage.getRecords(), FileVO.class);
        return new PageResp<>(fileVOList, filePage.getTotalRow());
    }

    @Override
    public void downloadFile(Long fileId, HttpServletResponse response){
        MFile mFile = fileMapper.selectFileByFileId(fileId);
        Assert.notNull(mFile, () -> new BusinessException(FileEnum.ErrorMsg.NONENTITY_FILE.getDesc()));
        MStorage storage = getStorage(mFile.getStorageId());
        FileHandler fileHandler = fileManager.getFileHandler(storage.getStorageType());
        fileHandler.downloadFile(mFile, storage, response);
    }

    @Override
    public FileVO getFileByFileId(Long fileId){
        MFile mFile = fileMapper.selectFileByFileId(fileId);
        Assert.notNull(mFile, () -> new BusinessException(
                FileEnum.ErrorMsg.NONENTITY_FILE.getDesc()));
        return BeanUtil.copyProperties(mFile, FileVO.class);
    }

    @Override
    public List<FileVO> getFileListByFileIds(List<Long> fileIds){
        List<MFile> mFiles = fileMapper.selectFileListByFileIds(fileIds);
        if (CollectionUtil.isNotEmpty(mFiles)){
            return BeanUtil.copyToList(mFiles, FileVO.class);
        }
        return List.of();
    }

    @Override
    public void updateStatusByFileUrl(FileUpdateStatusVO fileUpdateStatusVO){
        fileMapper.updateStatusByFileUrl(fileUpdateStatusVO.getUserId()
                , fileUpdateStatusVO.getFileUrlList()
                , fileUpdateStatusVO.getFileStatus());
    }

    @Override
    public void deleteBatchFiles(List<Long> fileIds){
        fileIds.forEach(this::deleteFile);
    }

    /**
     * 删除文件(不包含租户ID)
     *
     * @param fileId 文件ID
     */
    @Override
    public void deleteFileWithoutTenant(Long fileId){
        log.info("开始忽略租户条件删除文件，文件ID：{}", fileId);
        try{
            // 忽略租户条件
            TenantManager.ignoreTenantCondition();
            // 查询文件
            MFile mFile = fileMapper.selectFileByFileId(fileId);
            Assert.notNull(mFile, () -> new BusinessException(FileEnum.ErrorMsg.NONENTITY_FILE.getDesc()));
            MStorage storage = getStorage(mFile.getStorageId());
            FileHandler fileHandler = fileManager.getFileHandler(storage.getStorageType());
            // 删除文件
            fileHandler.deleteFile(mFile, storage);
            // 删除数据库文件记录
            LogicDeleteManager.execWithoutLogicDelete(() ->
                    fileMapper.deleteByQuery(QueryWrapper.create().eq(MFile::getFileId, fileId))
            );
            log.info("忽略租户条件删除文件成功，文件ID：{}", fileId);
        } catch (Exception e){
            log.error("忽略租户条件删除文件异常，文件ID：{}，异常信息：{}", fileId, e.getMessage(), e);
            throw e;
        } finally{
            // 确保恢复租户条件
            TenantManager.restoreTenantCondition();
            log.info("已恢复租户条件，文件ID：{}", fileId);
        }
    }

    /**
     * 批量删除文件(不包含租户ID)
     *
     * @param fileIds 文件ID列表
     */
    @Override
    public void deleteBatchFilesWithoutTenant(List<Long> fileIds){
        log.info("开始忽略租户条件批量删除文件，文件ID列表：{}", fileIds);
        if (CollectionUtil.isEmpty(fileIds)){
            log.info("文件ID列表为空，直接返回");
            return;
        }
        fileIds.forEach(this::deleteFileWithoutTenant);
        log.info("忽略租户条件批量删除文件成功，文件ID列表：{}", fileIds);
    }

    /**
     * 忽略租户条件获取文件信息
     *
     * @param fileIds 文件ID列表
     * @return 文件信息列表
     */
    @Override
    public List<FileVO> getFileListByFileIdsWithoutTenant(List<Long> fileIds){
        log.info("开始忽略租户条件获取文件信息，文件ID列表：{}", fileIds);
        // 如果文件ID列表为空，直接返回空列表
        if (CollectionUtil.isEmpty(fileIds)){
            log.info("文件ID列表为空，直接返回空列表");
            return List.of();
        }
        try{
            // 忽略租户条件
            TenantManager.ignoreTenantCondition();
            // 查询文件信息
            List<MFile> mFiles = fileMapper.selectFileByFileIds(fileIds);
            // 校验文件是否存在
            if (CollectionUtil.isEmpty(mFiles)){
                log.error("文件不存在，文件ID列表：{}", fileIds);
                return List.of();
            }
            log.info("忽略租户条件获取文件成功，文件ID列表：{}", fileIds);
            return BeanUtil.copyToList(mFiles, FileVO.class);
        } catch (Exception e){
            log.error("忽略租户条件获取文件异常，文件ID列表：{}, 异常信息：{}", fileIds, e.getMessage(), e);
            throw e;
        } finally{
            // 确保恢复租户条件
            TenantManager.restoreTenantCondition();
            log.info("已恢复租户条件，文件ID列表：{}", fileIds);
        }
    }

    /**
     * 忽略租户条件上传文件
     *
     * @param fileUploadVO 文件及携带参数
     * @return 文件信息
     */
    @Override
    public FileUploadRespVO uploadFileWithoutTenant(FileUploadVO fileUploadVO){
        log.info("开始忽略租户条件上传文件，文件名：{}", fileUploadVO.getFile().getOriginalFilename());
        try{
            // 忽略租户条件
            TenantManager.ignoreTenantCondition();

            // 获取存储信息
            MStorage storage = getStorage(null);
            Assert.notNull(storage, () -> new BusinessException(StorageEnum.ErrorMsg
                    .NONENTITY_STORAGE.getDesc()));

            // 获取文件处理器
            FileHandler fileHandler = fileManager.getFileHandler(
                    storage.getStorageType());

            // 上传文件
            MFile mFile = fileHandler.uploadFile(fileUploadVO.getFile()
                    , fileUploadVO.getFileSource(), storage);
            mFile.setCreateId(fileUploadVO.getCreateId());
            mFile.setUpdateId(fileUploadVO.getUpdateId());
            mFile.setTenantId(fileUploadVO.getTanantId());
            LocalDateTime now = LocalDateTime.now();
            mFile.setCreateTime(now);
            mFile.setUpdateTime(now);
            // 插入文件记录
            fileMapper.insert(mFile, true);

            log.info("忽略租户条件上传文件成功，文件ID：{}", mFile.getFileId());
            return BeanUtil.copyProperties(mFile, FileUploadRespVO.class);
        } catch (Exception e){
            log.error("忽略租户条件上传文件异常，文件名：{}，异常信息：{}",
                    fileUploadVO.getFile().getOriginalFilename(), e.getMessage(), e);
            throw new BusinessException(e.getMessage());
        } finally{
            // 确保恢复租户条件
            TenantManager.restoreTenantCondition();
            log.info("已恢复租户条件，文件名：{}", fileUploadVO.getFile().getOriginalFilename());
        }
    }

    /**
     * 获取存储信息
     *
     * @param storageId 存储ID
     * @return 存储信息
     */
    private MStorage getStorage(Long storageId){
        if (ObjectUtil.isNotNull(storageId)){
            return storageMapper.selectStorageByStorageId(storageId);
        }
        if (storageId == null){
            try{
                TenantManager.ignoreTenantCondition();
                return storageMapper.selectEnableStorage();
            } catch (Exception e){
                throw new BusinessException(e.getMessage());
            } finally{
                // 确保恢复租户条件
                TenantManager.restoreTenantCondition();
            }
        }
        //未指定存储，根据租户ID获取
        MTenant tenant = tenantMapper.selectTenantByTenantId(SafetyUtil.getLoginUserTenantId());
        if (tenant.getStorageId() == null){
            return storageMapper.selectEnableStorage();
        }
        Assert.notNull(tenant, () -> new BusinessException(TenantEnum.ErrorMsg.QUERY_NULL_TENANT.getDesc()));
        return storageMapper.selectStorageByStorageId(tenant.getStorageId());
    }

}
